import json
import re
from rest_framework import serializers
from django.core.mail import send_mail
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
from django.views import View
from redis import StrictRedis
from rest_framework import viewsets
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import BasePermission, IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly, AllowAny
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
from users.models import User, Area, Address
from django.contrib.auth import authenticate  # 此方法接收 request，username，passwrod，认证通过返回用户，否则返回空
from users.serializers import UserSerializer, AreaSerializer, AddressSerializer
# from users.users_utils import generate_verify_email_url, decode_email_token
from users.users_utils import generate_verify_email_url, decode_email_token


class RegisterView(View):
    def post(self, request):
        # 1. 接收参数  ajax请求,  接收的是 body中的  json数据
        data = json.loads(request.body.decode())

        username = data.get('username')
        password = data.get('password')
        password2 = data.get('password2')
        mobile = data.get('mobile')
        sms_code = data.get('sms_code')
        allow = data.get("allow")

        # 2. 校验参数
        # 判断参数是否齐全
        if not all([username, password, password2, mobile, sms_code, allow]):
            return JsonResponse({'code': '999', 'msg': '缺少必传参数'})
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return JsonResponse({'code': '999', 'msg': '请输入5-20个字符的用户名'})
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return JsonResponse({'code': '999', 'msg': '请输入8-20位的密码'})
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': '999', 'msg': '手机号码格式不正确'})
        if not sms_code:
            return JsonResponse({'code': '999', 'msg': '没有验证码'})
        # 判断两次密码是否一致
        if password != password2:
            return JsonResponse({'code': '999', 'msg': '两次输入的密码不一致'})
        # 判断是否勾选用户协议
        if not allow:
            return JsonResponse({'code': '999', 'msg': '请勾选用户协议'})

        # 判断手机验证码
        client = StrictRedis()
        redis_sms_code = client.get(mobile)
        if redis_sms_code:
            print("===================================================")
            print(redis_sms_code)
            print(redis_sms_code.decode())
            redis_sms_code = redis_sms_code.decode()
        else:
            redis_sms_code = None
        if sms_code == redis_sms_code:
            pass
        else:
            return JsonResponse({'code': '999', 'msg': '短信验证码错误'})

        # 3. 生成用户
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            return JsonResponse({'code': '999', 'msg': '注册失败'})
        # 4. 返回响应
        return JsonResponse({'code': '0', 'msg': 'ok', 'username': user.username, 'id': user.id, 'token': '000'})


class LoginView(View):
    def post(self, request):
        # 1. 接收参数
        data = json.loads(request.body.decode())

        username = data.get('username')
        password = data.get('password')
        # 2. 校验数据
        # 判断参数是否齐全
        if not all([username, password]):
            return JsonResponse({'code': '999', 'msg': '缺少必传参数'})
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return JsonResponse({'code': '999', 'msg': '请输入5-20个字符的用户名'})
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return JsonResponse({'code': '999', 'msg': '请输入8-20位的密码'})
        # 3. 认证用户
        user = authenticate(request, username=username, password=password)
        if user:
            return JsonResponse({'code': '0', 'msg': '认证成功',
                                 'username': user.username,
                                 'id': user.id,
                                 'token': '000'})
        else:
            return JsonResponse({'code': '999', 'msg': '认证错误'})
        # try:
        #     user = User.objects.get(username=username)
        # except Exception as e:
        #     return JsonResponse({'code': '999', 'msg': '用户不存在'})
        #
        # if user.check_password(password):
        #     return JsonResponse({'code': '0', 'msg': '登录成功',
        #                          'username': user.username,
        #                          'id': user.id,
        #                          'token': '000'})
        # else:
        #     return JsonResponse({'code': '999', 'msg': '密码错误'})


class UsernameCountView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return JsonResponse({'code': '0', 'msg': 'ok', 'count': count})


class MobileCountView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return JsonResponse({'code': '0', 'msg': 'ok', 'count': count})


class PageNum(PageNumberPagination):
    page_size_query_param = 'page_size'


class MyPermission(BasePermission):
    # 必须继承BasePermission
    def has_permission(self, request, view):
        """判断用户对模型有没有访问权"""
        if request.user.is_superuser:
            # 管理员对用户模型有访问权
            return True
        elif view.kwargs.get('pk') == str(request.user.id):
            # 携带的id和用户的id相同时有访问权
            return True
        return False

    # def has_object_permission(self, request, view, obj):
    #     """获取单个数据时,判断用户对某个数据对象是否有访问权限"""
    #     if request.user.id == obj.id:
    #         return True
    #     return False


# class UserView(APIView):
#     # 自定义限流类
#     throttle_classes = [UserRateThrottle]
#     permission_classes = (MyPermission,)  # 权限
#     def get(self, request):
#         # 获取id,
#         # 1, 根据id获取一个对象
#         # 2, 获取全部数据
#         # requset.POST, GET, body
#         # request.data
#         # 1, ajax, 标签请求, form,
#         # apiview 只能把body中的json数据转换到 request. data
#
#         pass


# class UserViewSet(viewsets.ModelViewSet):
#     """
#     完成产品的增删改查
#     """
#     queryset = User.objects.all()  # 视图集默认定义了数据,
#     serializer_class = UserSerializer  # 优先使用 get_serializer_class 返回的序列化器
#     # 增删改查, 必须建立在  数据集和序列化器之上,
#
#
#     # 自定义认证类, 自定义会覆盖全局配置
#     # authentication_classes = (JSONWebTokenAuthentication,)
#     # 自定义权限类
#     permission_classes = (IsAuthenticated,)
#     # permission_classes = (BasePermission,)
#     # 自定义限流类
#     throttle_classes = [UserRateThrottle]
#
#     # 指定过滤方法类, 排序方法类, 一个或多个
#     filter_backends = (DjangoFilterBackend, OrderingFilter)  # 同时支持过滤和排序
#
#     # 指定排序字段, 不设置, 排序功能不起效
#     ordering_fields = ('date_joined', 'id')
#
#     # 指定过滤字段, 不设置, 过滤功能不起效
#     filter_fields = ('username', 'phone', 'is_active')
#
#     # 自定义分页器 覆盖全局配置
#     pagination_class = PageNum
#
#     # 根据不同的请求, 获得不同的序列化器
#     def get_serializer_class(self):
#         # print(self.context)
#         # if self.action == 'partial_update':
#         #     return ProductPartialUpdateSerializer
#         if self.action == 'unactived':
#             return UserUnActiveSerializer
#         else:
#             return UserSerializer
#
#     #  get   /user/pk/  -> retrieve
#     #  get  /user/  -> list
#     #   get /user/unactived/   ->  unactived
#     @action(methods=['get'], detail=False)
#     def unactived(self, request, *args, **kwargs):
#         # 获取查询集, 过滤出未激活的用户
#         qs = self.queryset.filter(is_active=False)
#         # 使用序列化器, 序列化查询集, 并且是
#         ser = self.get_serializer(qs, many=True)
#
#         return Response(ser.data)


class UserViewSet(viewsets.ModelViewSet):
    """
    完成产品的增删改查
    """
    queryset = User.objects.all()  # 视图集默认定义了数据,
    serializer_class = UserSerializer  # 优先使用 get_serializer_class 返回的序列化器


class EmailAddView(APIView):
    # 自定义权限类
    # permission_classes = (IsAdminUser,)

    # 1. 获取email验证码的接口
    def post(self, request):
        # 1. 获取数据
        email = request.data.get('email')
        # 2. 校验数据
        pass
        # 3. 保存数据
        user = request.user
        user.email = email
        user.email_active = False
        user.save()
        # 4. 发送认证邮件
        # 4.1 生成token, 作为邮件内容
        verify_email_url = generate_verify_email_url(user.id)
        # 4.2 发送邮件
        send_mail(subject="激活邮件",
                  message='请点击以激活邮件:%s' % verify_email_url,
                  from_email='jx15147474523@163.com',
                  recipient_list=[user.email])
        pass
        # 5. 返回结果
        return Response({'code': 0, 'msg': '验证邮件发送成功'})


class EmailVerificationView(View):
    def get(self, request):
        token = request.GET.get('token')
        user_id = decode_email_token(token)
        if user_id:
            user = User.objects.get(id=user_id)
            user.email_active = True
            user.save()
            return HttpResponse('邮箱已激活')
        else:
            return HttpResponse('token失效')


class NoPageNum(PageNumberPagination):
    page_size_query_param = 'page_size'
    page_size = 1000


class AreaViewSet(viewsets.ModelViewSet):
    """
    完成产品的增删改查
    """
    queryset = Area.objects.all()  # 视图集默认定义了数据,
    serializer_class = AreaSerializer  # 优先使用 get_serializer_class 返回的序列化器

    pagination_class = NoPageNum
    # # http://127.0.0.1:8000/area/?parent=1    所有的省
    # # http://127.0.0.1:8000/area/?parent=110000    110000所有的市
    # # http://127.0.0.1:8000/area/?parent=110100    110100所有的区
    #
    # # 指定过滤字段, 不设置, 过滤功能不起效
    filter_fields = ('parent', 'id')


class AddressViewSet(viewsets.ModelViewSet):
    """
    完成产品的增删改查
    """
    queryset = Address.objects.all()  # 视图集默认定义了数据,
    serializer_class = AddressSerializer  # 优先使用 get_serializer_class 返回的序列化器

    pagination_class = NoPageNum
    # 生成url的情况
    # GET  http://127.0.0.1:8000/address/?id=n     过滤属于自己的地址
    # POST http://127.0.0.1:8000/address/  body{"user":"uid","":""}    增加新地址
    # PUT  http://127.0.0.1:8000/address/pk/  body{"":"","":""}    修改地址
    # DELETE  http://127.0.0.1:8000/address/pk/     删除地址

    # 指定过滤字段, 不设置, 过滤功能不起效
    filter_fields = ('user',)
